/**
 * \file IPartieConsole.c
 * \author Catalin BLAJ
 * \author Vincent JACQUEMIN
 * \date 07 Novembre 2013
 *
 * Fichier source IPartieConsole.c pour le programme du Sudoku
 */


#include "IPartieConsole.h"

/**
 * \brief Fonction de demande de ligne et colonne à l'utilisateur.
 * \param type : Type de la grille avec laquelle le joueur est en train de jouer (donnée).
 * \param symboles : Symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 * \return Renvoie l'entier correspondant à l'indice de la case.
 *
 * Demande à l'utilisateur l'indice de la ligne et de la colonne.
 */
static bool IP_verifierValiditeUnite(const SUnite* unite)
{
    /* Variables de convenance */
    unsigned char type = SU_getType(unite);
    unsigned nombreUnites = type*type;

    /* Vérification des paramètres */
    assert(unite != NULL);

    /* Double boucle pour vérifier si les unités sont valides */
    for(unsigned i=0; i<nombreUnites-1; i++)
    {
        for(unsigned j=i+1; j<nombreUnites; j++)
        {
            if(SC_getEtat(SU_getCase(unite, i)) != vide && SC_getEtat(SU_getCase(unite, j)) != vide)
            {
                if(SC_getValeur(SU_getCase(unite, i)) == SC_getValeur(SU_getCase(unite, j)))
                    return false;
            }
        }
    }

    return true;
}


int IP_demanderIndiceLigneColonne(unsigned char type, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned short nombreUnites = type*type;

    /* Vérification des paramètres */
    assert(symboles != NULL);
    assert(langue != NULL);

    /* Tant que l'indice de ligne rentré n'est pas correct, on lui demande de rentrer une valeur */
    char indiceLigne;
    bool incideCorrect = false;
    while (!incideCorrect)
    {
        IL_afficherRepliques(langue, 78); /* Entrez l'indice de la colonne */
        IL_afficherRepliques(langue, 81); /* (Entrez Espace pour revenir au menu principal) */
        scanf("%c", &indiceLigne);
        IO_viderBuffer();

        if (indiceLigne == ' ')
            return -1;
        if (SS_getIndice(symboles, indiceLigne) == -1)
        IL_afficherRepliques(langue, 80); /* L'indice entre ne correspond pas */
        else
            incideCorrect = true;
    }

    /* Tant que l'indice de colonne rentré n'est pas correct, on lui demande de rentrer une valeur */
    char indiceColonne;
    incideCorrect = false;
    while (!incideCorrect)
    {
        IL_afficherRepliques(langue, 79);
        IL_afficherRepliques(langue, 81); /* (Entrez Espace pour revenir au menu principal) */
        scanf("%c", &indiceColonne);
        IO_viderBuffer();

        if (indiceColonne == ' ')
            return -1;
        if (SS_getIndice(symboles, indiceColonne) == -1)
            IL_afficherRepliques(langue, 80); /* L'indice entre ne correspond pas */
        else
            incideCorrect = true;
    }

    /* On calcule l'indice de la case, et on le renvoie */
    int indiceCase = nombreUnites*(SS_getIndice(symboles, indiceLigne))+(SS_getIndice(symboles, indiceColonne));

    return indiceCase;
}


short IP_demanderValeur(const SSymboles* symboles, const Langue* langue)
{
    /* Vérification des paramètres */
    assert(symboles != NULL);
    assert(langue != NULL);

    /* Déclaration des variables*/
    char valeur;
    short valeurAlgo = 0;

    /* Tant qu'il n'a pas rentré une bonne valeur, on lui demande d'en saisir une */
    bool valeurCorrecte = false;
    while (!valeurCorrecte)
    {
        IL_afficherRepliques(langue, 84); /* Entrez le symbole que vous souhaitez inserer */
        IL_afficherRepliques(langue, 81); /* (Entrez Espace pour revenir au menu principal) */
        scanf("%c", &valeur);
        IO_viderBuffer();

        if (valeur == ' ')
            return -1;

        if (SS_getIndice(symboles, valeur) != -1)
        {
            valeurCorrecte = true;
            valeurAlgo = SS_getIndice(symboles, valeur);
        }
        else
            IL_afficherRepliques(langue, 85); /* Le caractere entre ne correspond pas */
    }

    return valeurAlgo;
}


/**
 * \brief Fonction de demande de candidats à l'utilisateur.
 * \param symboles : Symboles utilisés pour la partie (donnée).
 * \param candidats : Chaine de caractère entrée par l'utilisateur (donnée-résultat).
 * \param langue : Langue de la partie (donnée).
 *
 * Demande à l'utilisateur les candidats à traiter.
 */
static void IP_demanderCandidats(const SSymboles* symboles, char candidats[32], const Langue* langue)
{
    /* Vérification des paramètres */
    assert(symboles != NULL);
    assert(langue != NULL);

    /* Tant qu'il n'a pas rentré des candidats, on lui demande d'en saisir */
    bool candidatsCorrects = false;
    while (!candidatsCorrects)
    {
        IL_afficherRepliques(langue, 88); /* Entrez les candidats (a la suite sans espace) */
        IL_afficherRepliques(langue, 90); /* Entrez ! pour revenir au menu principal */
        scanf("%s", candidats);
        IO_viderBuffer();

        if (strcmp(candidats, "!") == 0)
            return;

        /* On traite la valeur rentré par l'utilisateur */
        candidatsCorrects = true;
        for(unsigned i=0; i<strlen(candidats); i++)
        {
            if (SS_getIndice(symboles, candidats[i]) == -1)
            {
                IL_afficherRepliques(langue, 89); /* Un candidat ne correspond pas aux symboles de la grille */
                candidatsCorrects = false;
                break;
            }
        }

        /* Si des erreurs sont détectées on affiche le message d'erreur */
        if (!candidatsCorrects)
            IO_pause(langue);
    }
}


/**
 * \brief Fonction vérification de victoire.
 * \param grille : la grille sur laquelle le joueur est en train de jouer (donnée).
 * \param grilleFinie : la grille solution (donnée).
 * \param gagne : Le booléen de victoire (donnée-résultat).
 *
 * Passe le booléen gagne à vrai si la grille est juste.
 */
static void IP_verifierVictoire(const SGrille* grille, const SGrille* grilleSolution, bool* gagne)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);
    unsigned nombreCases = type*type*type*type;

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(grilleSolution != NULL);

    /* Si une valeur est différente entre la grille en cours et la grille solution, on sort */
    for (unsigned i=0; i<nombreCases; i++)
    {
        if (SC_getValeur(SG_getCase(grille, i)) != SC_getValeur(SG_getCase(grilleSolution, i)))
            return;
    }

    *gagne = true;
}


/**
 * \brief Choix d'action.
 * \param langue : Langue de la partie (donnée).
 * \return Un entier correspondant à une action.
 *
 * Demande à l'utilisateur ce qu'il veut faire.
 */
static int IP_choixAction(const Langue* langue)
{
    int choix;

    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 93); /*  1- Remplir une case */
    IL_afficherRepliques(langue, 94); /*  2- Vider une case */
    IL_afficherRepliques(langue, 95); /*  3- Vider la grille */
    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 96); /*  4- Ajouter des candidats dans une case */
    IL_afficherRepliques(langue, 97); /*  5- Retirer des candidats dans une case */
    IL_afficherRepliques(langue, 98); /*  6- Remettre tous les candidats dans une case */
    IL_afficherRepliques(langue, 99); /*  7- Afficher les candidats d'une case */
    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 100); /*  8- Besoin d'aide ? */
    IL_afficherRepliques(langue, 101); /*  9- Verifier la grille en cours */
    IL_afficherRepliques(langue, 102); /* 10- Voir la solution */
    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 103); /* 11- Sauvegarder la partie */
    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 18); /*  0- Quitter la partie */
    IL_afficherRepliques(langue, 133);
    IL_afficherRepliques(langue, 36); /* Que voulez-vous faire */
    scanf("%d",&choix);
    IO_viderBuffer();

    return choix;
}


/**
 * \brief Réaction remplir case.
 * \param grille : Grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 * \param grilleSolution : Grille solution de la grille courante (donnée).
 * \param symboles : Symboles utilisés pour la partie (donnée).
 * \param gagne : Booléen de victoire (donnée).
 * \param langue : Langue de la partie (donnée-résultat).
 *
 * Effectue les actions nécéssaire pour remplir une case.
 */
static void IP_reactionRemplir(SGrille* grille, const SGrille* grilleSolution, const SSymboles* symboles, const Langue* langue, bool* gagne)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(grilleSolution != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort */
    int indiceCase = IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if (SC_getEtat(SG_getCase(grille, indiceCase)) != vide)
    {
        IL_afficherRepliques(langue, 41); /* La case contient déjà une valeur */
        IO_pause(langue);
        return;
    }

    /* On demande la valeur que la case doit prendre */
    int valeurAlgo = IP_demanderValeur(symboles, langue);
    if (valeurAlgo == -1)
        return;

    /* Tout est ok on affecte la valeur */
    SC_setEtat(SG_getCase(grille, indiceCase), valide);
    SC_setValeur(SG_getCase(grille, indiceCase), valeurAlgo);

    /* On vérifie si l'utilisateur a gagné */
    IP_verifierVictoire(grille, grilleSolution, gagne);
}


/**
 * \brief Réaction effacer valeur de cases.
 * \param grille : Grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 * \param symboles : Symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Effectue les actions nécéssaires pour vider une case.
 */
static void IP_reactionViderCase(SGrille* grille, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort */
    int indiceCase = IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if (SC_getEtat(SG_getCase(grille, indiceCase)) != valide)
    {
        IL_afficherRepliques(langue, 42); /* La case est vide ou gelée */
        IO_pause(langue);
        return;
    }

    /* Tout est ok, on vide la case */
    SC_setEtat(SG_getCase(grille, indiceCase), vide);
    SC_setValeur(SG_getCase(grille, indiceCase), -1);
}


/**
 * \brief Réaction vider grille
 * \param grille : Grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 *
 * Effectue les actions nécéssaires pour vider la grille
 */
static void IP_reactionViderGrille(SGrille* grille)
{
    /* Vérification des paramètres */
    assert(grille != NULL);

    int nombreCases = pow(SG_getType(grille), 4);

    /* On boucle sur les cases, on met à vide toutes celles qui sont valides */
    for (int i=0; i<nombreCases; i++)
    {
        if (SC_getEtat(SG_getCase(grille, i)) == valide)
        {
            SC_setEtat(SG_getCase(grille, i), vide);
            SC_setCandidats(SG_getCase(grille, i), 0) ;
            SC_setValeur(SG_getCase(grille, i), -1);
        }
    }
}


/**
 * \brief Réaction retirer tous candidat.
 * \param grille : Grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Effectue les actions nécéssaires pour enlever tous les candidats.
 */
static void IP_reactionAjouterCandidat(SGrille* grille, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort de la fonction */
    int indiceCase = IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if(SC_getEtat(SG_getCase(grille, indiceCase)) != vide)
    {
        IL_afficherRepliques(langue, 106); /* La case est valide ou gelée */
        IO_pause(langue);
        return;
    }

    /* On demande la valeur à mettre dans la case à l'utilisateur. Si le candidat est déjà présent, on sort */
    char candidats[32] = "";
    IP_demanderCandidats(symboles, candidats, langue);

    for (unsigned i=0; i<strlen(candidats); i++)
        SC_ajouterCandidat(SG_getCase(grille, indiceCase), SS_getIndice(symboles, candidats[i]));

    IL_afficherRepliques(langue, 107); /* Les candidats ont bien été retirés */
    IO_pause(langue);
}


/**
 * \brief Réaction retirer candidat.
 * \param grille : La grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Effectue les actions nécéssaires pour enlever un candidat.
 */
static void IP_reactionRetirerCandidat(SGrille* grille, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);

    /* Véfication des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort de la fonction */
    int indiceCase=IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if(SC_getEtat(SG_getCase(grille, indiceCase)) != vide)
    {
        IL_afficherRepliques(langue, 106); /* La case n'est est valide ou gelée */
        IO_pause(langue);
        return;
    }

    /* On demande la valeur à mettre dans la case à l'utilisateur. Si le candidat est déjà présent, on sort */
    char candidats[32] = "";
    IP_demanderCandidats(symboles, candidats, langue);

    for (unsigned i=0; i<strlen(candidats); i++)
        SC_retirerCandidat(SG_getCase(grille, indiceCase), SS_getIndice(symboles, candidats[i]));

    IL_afficherRepliques(langue, 108); /* Les candidats ont bien été retirés */
}


/**
 * \brief Réaction ajouter candidat.
 * \param grille : La grille avec laquelle le joueur est en train de jouer (donnée-résultat)
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Effectue les actions nécéssaires pour ajouter un candidat.
 */
static void IP_reactionReinitialiserCandidat(SGrille* grille, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort */
    int indiceCase=IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if(SC_getEtat(SG_getCase(grille, indiceCase)) != vide)
    {
        IL_afficherRepliques(langue, 106); /* La case n'est est valide ou gelée */
        IO_pause(langue);
        return;
    }

    SC_setCandidats(SG_getCase(grille, indiceCase), 0);
}


/**
 * \brief Réaction afficher candidats.
 * \param grille : La grille avec laquelle le joueur est en train de jouer (donnée).
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Affiche les candidats d'une case.
 */
static void IP_reactionAfficherCandidats(SGrille* grille, const SSymboles* symboles, const Langue* langue)
{
    /* Variable de convenance */
    unsigned char type = SG_getType(grille);
    unsigned nombreCandidats = type*type;

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);

    /* On demande l'indice de la ligne et de la colonne à l'utilisateur. Si la case est n'est pas vide, on sort */
    int indiceCase=IP_demanderIndiceLigneColonne(type, symboles, langue);
    if (indiceCase == -1)
        return;

    if(SC_getEtat(SG_getCase(grille, indiceCase)) != vide)
    {
        IL_afficherRepliques(langue, 106); /* La case n'est est valide ou gelée */
        IO_pause(langue);
        return;
    }

    if (SC_getNombreCandidats(SG_getCase(grille, indiceCase)) == 0)
    {
        IL_afficherRepliques(langue, 138); /* La case ne contient pas de candidat */
        IO_pause(langue);
    }
    else
    {
        IL_afficherRepliques(langue, 109); /* Les candidats de la case sont */
        /* On boucle sur les candidats de la case, si un candidat est présent, on l'affiche */
        for (unsigned i=0; i<nombreCandidats; i++)
        {
            if(SC_getCandidat(SG_getCase(grille, indiceCase), i))
                printf("%c ", SS_getSymbole(symboles, i));
        }
    }
    IL_afficherRepliques(langue, 133);
    IO_pause(langue);
}


/**
 * \brief Reaction Hint.
 * \param grille : La grille avec laquelle le joueur est en train de jouer (donnée-résultat).
 * \param grilleFinie : La grille solution (donnée).
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langue : Langue de la partie (donnée).
 *
 * Dévoile la case qui a le moins de candidats.
 */
static void IP_reactionHint(SGrille* grille, const SGrille* grilleSolution, const SSymboles* symboles, const Langue* langue)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);
    unsigned short nombreUnites = type*type;
    unsigned nombreCases = nombreUnites*nombreUnites;
    unsigned minimumCandidats = nombreUnites;

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(grilleSolution != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    IL_afficherRepliques(langue, 112); /* Souhaitez-vous qu'une case de la grille soit devoilee ? */
    IL_afficherRepliques(langue, 113); /* 1- OUI */
    IL_afficherRepliques(langue, 114); /* 2- NON */
    int choix = 0;
    while ((choix != 1) && (choix != 2))
    {
        scanf("%d", &choix);
        IO_viderBuffer();
        if ((choix != 1) && (choix != 2))
        {
            IL_afficherRepliques(langue, 115); /* La valeur n'est pas comprise entre 1 et 2 */
            IO_pause(langue);
        }
    }

    /* Si l'utilisateur souhaite voir une case se dévoiler */
    if (choix == 1)
    {
        /* On copie la grille pour trouver la case possédant le moins de candidats */
        SGrille* grilleCopie = SG_initialiserCopie(grille);
        int indiceCase = 0;

        for (unsigned i=0; i<nombreCases; i++)
        {
            if (SC_getEtat(SG_getCase(grilleCopie, i)) == valide)
                SC_reinitialiserCandidats(SG_getCase(grilleCopie, i));
        }

        /* On parcourt la grille pour récupérer l'indice de la bonne case */
        for (unsigned i=0; i<nombreCases; i++)
        {
            if (SC_getEtat(SG_getCase(grilleCopie, i)) == vide)
            {
                UG_miseAJourCandidat(grilleCopie, SG_getCase(grilleCopie, i));
                if (SC_getNombreCandidats(SG_getCase(grilleCopie, i)) < minimumCandidats)
                {
                    indiceCase = SC_getIndice(SG_getCase(grilleCopie, i));
                    minimumCandidats = SC_getNombreCandidats(SG_getCase(grilleCopie, i));
                }
            }
        }

        SG_testament(grilleCopie);

        /* On valide la case de la grille originale */
        SC_setCandidats(SG_getCase(grille, indiceCase), 0);
        SC_setValeur(SG_getCase(grille, indiceCase), pow2(SC_getValeur(SG_getCase(grilleSolution, indiceCase))));
        SC_setEtat(SG_getCase(grille, indiceCase), valide);

        IL_afficherRepliques(langue, 116); /* Une case a été dévoilée */
        IO_pause(langue);
    }

    /* Sinon, on sort */
    else
        return;
}


bool IP_reactionVerifierValiditeGrille(const SGrille* grille)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);
    unsigned nombreUnites = type*type;

    /* Vérification des paramètres */
    assert(grille != NULL);

    for(unsigned  i=0; i<nombreUnites; i++)
    {
            if(!IP_verifierValiditeUnite(SG_getLigne(grille, i)))
                return false;

            if(!IP_verifierValiditeUnite(SG_getColonne(grille, i)))
                return false;

            if(!IP_verifierValiditeUnite(SG_getRegion(grille, i)))
                return false;
    }

    return true;
}


void IP_afficherGrille(const SGrille* grille, const SSymboles* symboles)
{
    /* Variables de convenance */
    unsigned char type = SG_getType(grille);
    unsigned nombreUnites = type*type;

    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(symboles != NULL);

    /* Boucle des indices de colonnes */
    printf("  ");
    for (unsigned i=0; i<nombreUnites; i++)
    {
        printf("%c ", SS_getSymbole(symboles, i));
        if ((i%type) == (unsigned) type-1)
            printf(" ");
    }
    printf("\n");

    /* Boucle des lignes */
    for (unsigned i=0; i<nombreUnites; i++)
    {
        if (i%type == 0)
        {
            printf(" |");
            for (unsigned i=1; i<2*(nombreUnites+(type-1))-(type-2); i++)
                printf("-");
            printf("|\n");
        }

        /* Sous-boucle des indices de ligne et affichage des valeurs de cases */
        for (unsigned j=0; j<nombreUnites; j++)
        {
            if (j%type == 0)
            {
                if (j == 0)
                    printf("%c|", SS_getSymbole(symboles, i));
                else
                    printf("|");
            }

            /* Affichage des valeurs */
            if (SC_getEtat(SU_getCase(SG_getLigne(grille, i), j)) == vide)
                printf("  ");
            else if (SC_getEtat(SU_getCase(SG_getLigne(grille, i), j)) == gele)
            {
            #ifdef _WIN32 /* Coloration des révélés sur Windows */
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 3);
                printf("%c ", SS_getSymbole(symboles, SC_getValeur(SU_getCase(SG_getLigne(grille, i), j))));
                SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
            #else /* Coloration des révélés sur Linux */
				couleur("34");
                printf("%c ", SS_getSymbole(symboles, SC_getValeur(SU_getCase(SG_getLigne(grille, i), j))));
			    couleur("0");
            #endif
            }
            else
                printf("%c ", SS_getSymbole(symboles, SC_getValeur(SU_getCase(SG_getLigne(grille, i), j))));
        }
        /* Fermeture à droite */
        printf("|");
        printf("\n");
    }

    /* Boucle de la ligne du bas */
    printf(" |");
    for (unsigned i=1; i<2*(nombreUnites+(type-1))-(type-2); i++)
        printf("-");
    printf("|\n");
}


/**
 * \brief Fonction d'affichage de solution.
 * \param grilleSolution : La solution de la grille (donnée).
 * \param symboles : Les symboles utilisés pour la partie (donnée).
 * \param langues : Langue de la partie (donnée).
 * \param abandon : Le booléen d'abandon (donnée-résultat).
 *
 * Affiche la grille solution.
 */
static void IP_afficherSolution(const SGrille* grilleSolution, const SSymboles* symboles, const Langue* langue, bool* abandon)
{
    /* Vérification des paramètres */
    assert(grilleSolution != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* On affiche la grille solution */
    IP_afficherGrille(grilleSolution, symboles);
    IO_pause(langue);

    /* Si l'utilisateur regarde la solution, alors il abandonne */
    *abandon = true;
}


/**
 * \brief Fonction de sauvegarde.
 * \param grille : La grille sur laquelle le joueur est en train de jouer (donnée).
 * \param grilleFinie : la grille solution (donnée).
 * \param langue : Langue de la partie (donnée).
 * \return Renvoie vrai si la partie a été sauvegardée, faux sinon.
 *
 * Sauvegarde la partie en cours et renvoie vrai si la sauvegarde s'est correctement déroulée.
 */
static bool IP_reactionSauvegarder(const SGrille* grille, const SGrille* grilleSolution, const Langue* langue)
{
    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(grilleSolution != NULL);
    assert(langue != NULL);

    /* On créée le dossier de sauvegarde s'il n'existe pas */
    char chemin[256] = "sauvegardes/";
#ifdef _WIN32
    mkdir(chemin);
#else
    mkdir(chemin, 2);
#endif

    /* Déclaration des variables */
    char* chaineGrille = SG_toChaine(grille);
    char* chaineGrilleSolution = SG_toChaine(grilleSolution);
    char separateur[2] = "%";
    char buffer[256];
    time_t timestamp = time(NULL);

    /* Nom du fichier formaté avec la date et l'heure */
    strftime(buffer, sizeof(buffer), "%d%m%y%H%M%S", localtime(&timestamp));

    /* On crée le fichier */
    strcat(chemin, buffer);
    FILE* fichierSauvegarde = fopen(chemin, "w");
    if (fichierSauvegarde == NULL)
        return false;

    /* On place la chaine formatée de la grille en cours et de la solution séparées par '%' */
    strcat(chaineGrille, separateur);
    strcat(chaineGrille, chaineGrilleSolution);
    fputs(chaineGrille, fichierSauvegarde);

    /* Libération de mémoire. */
    free(chaineGrille);
    free(chaineGrilleSolution);

    fclose(fichierSauvegarde);

    return true;
}


void IP_reactionQuitter(bool* quitter)
{
    /* Passage du booléen de fin de session à vrai */
    *quitter = true;
}


void IP_session(SGrille* grille, SGrille* grilleSolution, SSymboles* symboles, const Langue* langue)
{
    /* Vérification des paramètres */
    assert(grille != NULL);
    assert(grilleSolution != NULL);
    assert(symboles != NULL);
    assert(langue != NULL);

    /* Tant que l'utilisateur n'a pas quitté ni gagné */
    bool quitter = false;
    bool abandon = false;
    bool gagne = false;
    while (!quitter && !abandon && !gagne)
    {
        /* On affiche la grille de jeu */
        IO_effacerEcran();
        IP_afficherGrille(grille, symboles);

        /* Et on affiche le choix de jeu */
        switch (IP_choixAction(langue))
        {
            case 1:
                IP_reactionRemplir(grille, grilleSolution, symboles, langue, &gagne);
                break;

            case 2:
                IP_reactionViderCase(grille, symboles, langue);
                break;

            case 3:
                IP_reactionViderGrille(grille);
                break;

            case 4:
                IP_reactionAjouterCandidat(grille, symboles, langue);
                break;

            case 5:
                IP_reactionRetirerCandidat(grille, symboles, langue);
                break;

            case 6:
                IP_reactionReinitialiserCandidat(grille, symboles, langue);
                break;

            case 7:
                IP_reactionAfficherCandidats(grille, symboles, langue);
                break;

            case 8:
                IP_reactionHint(grille, grilleSolution, symboles, langue);
                break;

            case 9:
                if (IP_reactionVerifierValiditeGrille(grille))
                {
                    IL_afficherRepliques(langue, 128); /* La grille est valide pour le moment */
                    IO_pause(langue);
                }
                else
                {
                    IL_afficherRepliques(langue, 129); /* La grille n'est pas valide */
                    IO_pause(langue);
                }
                break;

            case 10:
                IP_afficherSolution(grilleSolution, symboles, langue, &abandon);
                break;

            case 11:
                if (IP_reactionSauvegarder(grille, grilleSolution, langue))
                {
                    IL_afficherRepliques(langue, 125); /* La partie a été sauvegardée */
                    IO_pause(langue);
                }
                else
                {
                    IL_afficherRepliques(langue, 124); /* Le fichier n'a pas pu être créé */
                    IO_pause(langue);
                }
                break;

            case 0:
                IP_reactionQuitter(&quitter);
                break;

            default:
                IL_afficherRepliques(langue, 10); /* Le choix entre est incorrect */
                IO_pause(langue);
                break;

            /* Si le joueur a gagné, on affiche la solution et on lui indique sa victoire */
            if (gagne)
            {
                IO_effacerEcran();
                IP_afficherGrille(grilleSolution, symboles);
                IL_afficherRepliques(langue, 132); /* VOUS AVEZ GAGNE. FELICITATIONS */
            }
        }
    }

    /* Libération de mémoire */
    SG_testament(grille);
    SG_testament(grilleSolution);
    SS_testament(symboles);
}
